package com.xqiapp.xframe.plugin.codes.gen;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xqiapp.xframe.plugin.codes.ClassGenrater;
import com.xqiapp.xframe.plugin.codes.Clazz;
import com.xqiapp.xframe.plugin.codes.Methods;
import com.xqiapp.xframe.plugin.codes.scan.ClassScanner;
import com.xqiapp.xframe.plugin.codes.scan.impl.TestInterfaceScanner;
import com.xqiapp.xframe.plugin.codes.util.ValidUtil;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

/**
 * 自动生成测试代码的处理器
 * 
 * @author mike
 * @date 2016年7月14日
 * @version 0.0.1
 */
public class AutoTestClassGenraterHandler implements IGenraterHandler {
	
	private static final Logger LOG = LoggerFactory.getLogger(AutoTestClassGenraterHandler.class);
	
	@Override
	public void handle(String scanPkg, String outPkg, String tempFileDir, String tempFileName) throws IOException, TemplateException {
		Configuration tempConfig = new Configuration();
		tempConfig.setClassForTemplateLoading(ClassGenrater.class, "/" + tempFileDir);
		generateTestClass(tempConfig, scanPkg, outPkg, tempFileName);
	}

	/**
	 * 生成测试类
	 * 
	 * @param tempConfig
	 * @throws IOException
	 * @throws TemplateException
	 */
	private void generateTestClass(Configuration tempConfig, String scanPkg, String outPkg, String tempFileName) throws IOException,
			TemplateException {
		List<Class<?>> interfaceList = getInterfaceList(scanPkg);
		
		LOG.info("Scan interface size: "+interfaceList.size());
		
		if (ValidUtil.isEmpty(interfaceList))
			throw new RuntimeException("[test]:None interface class of the system");

		Template temp = tempConfig.getTemplate(tempFileName);

		String outdir = this.getPath(outPkg).replaceAll("%20", " ") + "/" + outPkg.replace(".", "/");
		
		StringBuffer sb = new StringBuffer();
		for (Class<?> service : interfaceList) {
			Clazz clazz = new Clazz();
			clazz.setConfigPath(ClassGenrater.CONFIG_FILE_PATH);
			String serviceName = service.getSimpleName();
			clazz.setInterfaceName(serviceName);
			String serviceImplName = "";
			if (serviceName.indexOf("I") == 0)
				serviceImplName = serviceName.substring(1, serviceName.length());
			else
				serviceImplName = serviceName;
			
			clazz.setDeclName("m" + serviceImplName);
			clazz.setInterfaceImplName(serviceImplName);
			clazz.setPkg(outPkg);
			// 获取方法
			List<Methods> mList = getMethods(service);
			clazz.setMethods(mList);
			String outfile = serviceImplName + "Test.java";
			sb.append(outfile+",");
			Map<String, Object> root = new HashMap<String, Object>();
			root.put("clazz", clazz);
			generate(root, temp, outfile, outdir);
		}
		
		LOG.info("[End Genrater] [File list]:"+sb.toString());
	}

	/**
	 * 获取接口列表
	 * 
	 * @return
	 */
	private List<Class<?>> getInterfaceList(String scanPkg) {
		ClassScanner cs = new TestInterfaceScanner();
		return cs.getInterfaceList(scanPkg);
	}

	/**
	 * 获取封装后的方法列表
	 * 
	 * @param service
	 * @return
	 */
	private List<Methods> getMethods(Class<?> service) {
		Method[] methodArr = service.getMethods();
		List<Methods> mList = new ArrayList<Methods>(methodArr.length);
		for (Method method : methodArr) {
			Methods m = new Methods();
			m.setName(method.getName());
			// 获取返回值类型
			Class<?> rType = method.getReturnType();
			if(!rType.getName().contains("void")){
				m.setReturnType(rType.getName());
				m.setReturnDecl("m" + rType.getSimpleName());
			}else{
				m.setReturnType("");
				m.setReturnDecl("");
			}
			
			// 获取参数列表
			Class<?>[] argsTypes = method.getParameterTypes();
			Map<String, String> argsTypeMap = new HashMap<String, String>(argsTypes.length);
			List<String> argsNameList = new ArrayList<String>(argsTypes.length);
			for (int i = 0; i < argsTypes.length; i++) {
				String argName = "args" + i;
				argsNameList.add(argName);
				argsTypeMap.put(argName, argsTypes[i].getName());
			}
			m.setArgsNames(argsNameList);
			m.setArgsTypes(argsTypeMap);
			m.setArgSize(argsNameList.size());
			mList.add(m);
		}
		return mList;
	}

	/**
	 * 生成
	 * 
	 * @param root
	 * @param temp
	 * @param outfilename
	 * @param outdir
	 * @throws IOException
	 * @throws TemplateException
	 */
	public void generate(Map<String, Object> root, Template temp, String outfilename, String outdir) throws IOException, TemplateException {
		File outDirFile = new File(outdir);
		outDirFile.mkdirs();
		File file = new File(outDirFile.getPath().replaceAll("%20", " ") + "/" + outfilename);
		file.createNewFile();
		FileOutputStream fos = new FileOutputStream(file);
		Writer out = new OutputStreamWriter(fos);
		temp.process(root, out);
		out.flush();
		out.close();
	}

	/**
	 * 获取本地目录放生成的文件
	 * 
	 * @return
	 * @throws FileNotFoundException
	 */
	public String getPath(String outPkg) throws FileNotFoundException {
		String path = ClassGenrater.class.getResource("/").getPath().replaceAll("%20", " ");
		path = path.substring(0, path.indexOf("target/"));

		if (outPkg.indexOf("test") >= 0)
			path += "src/test/java/";
		else
			path += "src/main/java/";

		File outFile = new File(path);
		if (outFile.exists()) {
			outFile.delete();
		}
		return outFile.getPath().replaceAll("%20", " ");
	}
}
